#include "../include/Socket.h"
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <fcntl.h>
#include <arpa/inet.h>
#include "../include/Logger.h"
#include <string.h>

Socket::Socket()
    : _sockfd(-1)
{
}
Socket::Socket(int fd)
    : _sockfd(fd)
{
}

Socket::~Socket()
{
    Close();
}

int Socket::Fd()
{
    return _sockfd;
}

void Socket::Close()
{
    if (_sockfd != -1)
        close(_sockfd);
    _sockfd = -1;
}

bool Socket::Create()
{
    int ret = socket(AF_INET, SOCK_STREAM, 0);
    if (ret < 0)
    {
        ERR_LOG("创建套接字失败: %s", strerror(errno));
        return false;
    }
    _sockfd = ret;
    return true;
}

bool Socket::Bind(const std::string &ip, uint16_t port)
{
    struct sockaddr_in addr;
    addr.sin_port = htons(port);
    addr.sin_family = AF_INET;
    addr.sin_addr.s_addr = inet_addr(ip.c_str());
    int ret = bind(_sockfd, (const sockaddr *)&addr, sizeof(addr));
    if (ret < 0)
    {
        ERR_LOG("绑定套接字失败: %s", strerror(errno));
        return false;
    }
    return true;
}

bool Socket::Listen(int backlog)
{
    int ret = listen(_sockfd, backlog);
    if (ret < 0)
    {
        ERR_LOG("监听套接字失败: %s", strerror(errno));
        return false;
    }
    return true;
}

// 像服务器发起链接
bool Socket::Connect(const std::string &ip, uint16_t port)
{
    struct sockaddr_in addr;
    addr.sin_addr.s_addr = inet_addr(ip.c_str());
    addr.sin_family = AF_INET;
    addr.sin_port = htons(port);
    int ret = connect(_sockfd, (const sockaddr *)&addr, sizeof(addr));
    if (ret < 0)
    {
        ERR_LOG("向服务器发起连接失败：%s", strerror(errno));
        return false;
    }

    return true;
}

int Socket::Accept()
{
    int newfd = accept(_sockfd, NULL, NULL);
    if (newfd < 0)
    {
        ERR_LOG("获取新连接失败: %s", strerror(errno));
        return -1;
    }
    return newfd;
}

ssize_t Socket::Recv(void *buffer, size_t len, int flag) // flag=0 默认阻塞
{
    int n = recv(_sockfd, buffer, len, flag);
    if (n == 0)
    {
        // 等于0表示连接断开了
        DBG_LOG("连接断开了");
        return -1;
    }
    if (n < 0) //小于0的时候表示读出错了
    {
        if (errno == EAGAIN || errno == EINTR)
        {
            //EAGAIN    表示当前socket的接收缓冲区中没有数据，在非阻塞情况下才会出现这种错误
            //EINTR     表示当前socket的阻塞等待被信号打断了
            return 0; //表示这次没有接收到数据
        }
        ERR_LOG("读取套接字数据失败");
        return -1;
    }
    return n;
}

ssize_t Socket::NonBlockRecv(void *buffer, size_t len)
{
    return Recv(buffer, len, MSG_DONTWAIT);
}

ssize_t Socket::Send(const void *buffer, size_t len, int flag)
{
    int n = send(_sockfd, buffer, len, flag);
    if (n < 0)
    {
        if (errno == EAGAIN || errno == EINTR)
            return 0;
        ERR_LOG("给套接字发送数据失败");
        return -1;
    }
    return n;
}
ssize_t Socket::NonBlockSend(void *buf, size_t len)
{
    return send(_sockfd, buf, len, MSG_DONTWAIT);
}

bool Socket::CreateServer(uint16_t port, const std::string &ip, bool block_flag)
{
    // 创建套接字
    if (Create() == false)
        return false;
    if (block_flag == true)
        NonBlock();
    // 设置端口复用
    ReuseAddress();
    // 绑定地址
    if (Bind(ip, port) == false)
        return false;
    // 开始监听
    if (Listen() == false)
        return false;
    return true;
}

bool Socket::CreateClient(uint16_t port, const std::string ip)
{
    // 创建套接字
    if (Create() == false)
        return false;
    if (Connect(ip, port) == false)
        return false;
    return true;
}

//设置套接字选项 -- 开启端口复用
void Socket::ReuseAddress()
{
    int val = 1;
    setsockopt(_sockfd, SOL_SOCKET, SO_REUSEPORT | SO_REUSEADDR, &val, sizeof(val));
    val = 1;
    setsockopt(_sockfd, SOL_SOCKET, SO_REUSEPORT, (void *)&val, sizeof(int));
}

void Socket::NonBlock()
{
    int flag = fcntl(_sockfd, F_GETFL, 0);
    fcntl(_sockfd, F_SETFL, flag | O_NONBLOCK);
}